package dice.sinanya.start;

import dice.sinanya.db.tools.SqliteUtil;
import dice.sinanya.tools.getinfo.SystemType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nlpcn.commons.lang.util.StringUtil;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.sql.*;
import java.util.ArrayList;

import static dice.sinanya.SinaNya.systemType;
import static dice.sinanya.system.MessagesSystem.entityDevice;
import static dice.sinanya.system.MessagesSystem.loginInfo;

public class MiraiConfig implements FindDir {
    private static final Logger logger = LogManager.getLogger(MiraiConfig.class.getName());
    SqliteUtil sqliteUtil;

    public MiraiConfig() {
        sqliteUtil = new SqliteUtil();
    }

    public static byte[] getEntityDevice(String key, byte[] defaultValue) {
        return (byte[]) entityDevice.getOrDefault(key, defaultValue);
    }

    public static String getEntityDevice(String key, String defaultValue) {
        return String.valueOf(entityDevice.getOrDefault(key, defaultValue));
    }

    public static byte[] getEntityDevice(String key) {
        return (byte[]) entityDevice.getOrDefault(key, "".getBytes());
    }

    public static String getEntityDeviceString(String key, String defaultValue) {
        return String.valueOf(entityDevice.getOrDefault(key, defaultValue));
    }

    public static String getEntityDeviceString(String key) {
        return String.valueOf(entityDevice.getOrDefault(key, ""));
    }

    public void init() {
        try (Connection connection = sqliteUtil.getConnection()) {
            try (Statement statement = connection.createStatement()) {
                statement.executeUpdate("create table if not exists miraiLogin(qqId long,password varchar(200),PRIMARY KEY (qqId));");
                statement.executeUpdate("create table if not exists miraiDevice(qqId long,fingerprint blob,bootId blob,procVersion blob,imsiMd5 blob,imei blob,PRIMARY KEY (qqId));");
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(), throwables);
        }
    }

    public void flushLogin() {
        try (Connection connection = sqliteUtil.getConnection()) {
            try (Statement statement = connection.createStatement()) {
                //language=SQLite
                String sql="select * from miraiLogin";
                try (ResultSet resultSet = statement.executeQuery(sql)) {
                    if (resultSet.next()) {
                        loginInfo.setLoginId(resultSet.getLong("qqId"));
                        loginInfo.setPasswd(resultSet.getString("password"));
                    }
                }
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(), throwables);
        }
    }

    public void flushDevice() {
        try (Connection connection = sqliteUtil.getConnection()) {
            //language=SqLite
            String sql = "select * from miraiDevice where qqId=?";
            try (PreparedStatement statement = connection.prepareStatement(sql)) {
                statement.setLong(1, loginInfo.getLoginId());
                try (ResultSet resultSet = statement.executeQuery()) {
                    if (resultSet.next()) {
                        entityDevice.put("fingerprint", resultSet.getBytes("fingerprint"));
                        entityDevice.put("bootId", resultSet.getBytes("bootId"));
                        entityDevice.put("procVersion", resultSet.getBytes("procVersion"));
                        entityDevice.put("imsiMd5", resultSet.getBytes("imsiMd5"));
                        entityDevice.put("imei", resultSet.getBytes("imei"));
                    }
                }
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(), throwables);
        }
    }

    public void insertLogin() {
        try (Connection connection = sqliteUtil.getConnection()) {
            //language=SQLite
            String sql="delete from miraiLogin";
            try (PreparedStatement statement = connection.prepareStatement(sql)) {
                statement.executeUpdate();
            }
            //language=SQLite
            sql = "insert into miraiLogin(qqId,password) values(?,?);";
            try (PreparedStatement statement = connection.prepareStatement(sql)) {
                statement.setLong(1, loginInfo.getLoginId());
                statement.setString(2, loginInfo.getPasswd());
                statement.executeUpdate();
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(), throwables);
        }
    }

    public void insertDevice() {
        try (Connection connection = sqliteUtil.getConnection()) {
            //language=SQLite
            String sql = "replace into miraiDevice(qqId,fingerprint,bootId,procVersion,imsiMd5,imei) values(?,?,?,?,?,?)";
            try (PreparedStatement statement = connection.prepareStatement(sql)) {
                statement.setLong(1, loginInfo.getLoginId());
                statement.setBytes(2, getEntityDevice("fingerprint"));
                statement.setBytes(3, getEntityDevice("bootId"));
                statement.setBytes(4, getEntityDevice("procVersion"));
                statement.setBytes(5, getEntityDevice("imsiMd5"));
                statement.setString(6, getEntityDeviceString("imei"));
                statement.executeUpdate();
            }
        } catch (SQLException throwables) {
            logger.error(throwables.getMessage(), throwables);
        }
    }

    @Override
    public File findDir(String fileName) throws IOException {
        File myDir = findMyDir();
        ArrayList<String> pathStr = new ArrayList<>();
        if (!"login.cfg".equals(fileName)) {
            if (systemType.equals(SystemType.WIN)) {
                pathStr.add("SinaNya");
            }
            pathStr.add("conf");
        }
        pathStr.add(fileName);
        return new File(URLDecoder.decode(myDir.getPath(), "UTF-8"), StringUtil.joiner(pathStr, File.separator));
    }
}
